package task

import (
	"errors"

	"github.com/robfig/cron"
)

/**
Field name   | Mandatory? | Allowed values  | Allowed special characters
----------   | ---------- | --------------  | --------------------------
Seconds      | Yes        | 0-59            | * / , -
Minutes      | Yes        | 0-59            | * / , -
Hours        | Yes        | 0-23            | * / , -
Day of month | Yes        | 1-31            | * / , - ?
Month        | Yes        | 1-12 or JAN-DEC | * / , -
Day of week  | Yes        | 0-6 or SUN-SAT  | * / , - ?
*/

type Status int

const (
	RUN   Status = 0
	PAUSE Status = 1
	STOP  Status = -1
)

var taskManager = make(map[string]*Task, 0)

func AddTask(task *Task) error {
	if task.UniqueId == "" {
		return errors.New("unique id must not be empty")
	}
	if task.Cron == "" {
		return errors.New("cron must not be empty")
	}
	if task.R == nil {
		return errors.New("R must not be empty")
	}

	_, ok := taskManager[task.UniqueId]
	if ok {
		return errors.New("the task repeat")
	}
	taskManager[task.UniqueId] = task
	task.scheduler.Start()
	return nil
}

func GetTask(uniqueId string) *Task {
	t, ok := taskManager[uniqueId]
	if !ok {
		return nil
	}
	return t
}

func RemoveTask(uniqueId string) {
	_, ok := taskManager[uniqueId]
	if ok {
		taskManager[uniqueId] = nil
	}
}

type Task struct {
	UniqueId  string                 // 唯一ID
	Name      string                 // 任务名称
	Group     string                 // 任务分组
	Status    int                    // 任务状态
	Cron      string                 // cron表达式
	Type      string                 // 任务类型
	R         func(t *Task)          // 执行此任务的函数
	Data      map[string]interface{} // 任务携带的数据
	jobStatus Status                 // 任务状态
	scheduler *cron.Cron             // 调度器
}

func NewTaskWithCronAndCmd(spec string, cmd func(t *Task)) *Task {
	job := &Task{
		scheduler: cron.New(),
		Cron:      spec,
		R:         cmd,
	}
	return job
}

func (t *Task) Run() {
	if t.jobStatus == PAUSE {
		return
	}
	if t.R == nil {
		panic(errors.New("the job R must be not empty"))
	}
	t.R(t)
}

func (t *Task) Pause() {
	t.jobStatus = PAUSE
}

func (t *Task) Start() {
	t.jobStatus = RUN
	t.scheduler.Start()
}

func (t *Task) StartTask() error {
	err := t.scheduler.AddJob(t.Cron, t)
	if err != nil {
		return err
	}
	t.scheduler.Start()
	return nil
}

func (t *Task) Stop() {
	t.scheduler.Stop()
}
